﻿'Copyright (c) 2008, Jonathan Allen

Imports ClrExtensions.VBLanguageExtension
Imports ClrExtensions.Net.Rest

''' <summary>
''' 
''' </summary>
''' <remarks>User isn't necessarily thread-safe</remarks>
Public Class User
    Implements IAccessToken
    Private m_AccessToken As AccessToken
    Private m_Connection As NetflixConnection

    Public Sub New(ByVal userId As String, ByVal token As String, ByVal tokenSecret As String, ByVal connection As NetflixConnection)
        m_AccessToken = New AccessToken(userId, token, tokenSecret)
        m_Connection = connection
    End Sub

    Public Sub New(ByVal accessToken As AccessToken, ByVal connection As NetflixConnection)
        m_AccessToken = accessToken
        m_Connection = connection
    End Sub

    Public ReadOnly Property UserId() As String Implements IAccessToken.UserId
        Get
            Return AccessToken.UserId
        End Get
    End Property

    Public ReadOnly Property AccessToken() As AccessToken
        Get
            Return m_AccessToken
        End Get
    End Property

    Public ReadOnly Property Connection() As NetflixConnection
        Get
            Return m_Connection
        End Get
    End Property

    Public ReadOnly Property DiscQueue() As DiscQueue
        Get
            Static m_DiscQueue As New DiscQueue(Me)
            Return m_DiscQueue
        End Get
    End Property

    Public ReadOnly Property InstantQueue() As InstantQueue
        Get
            Static m_InstantQueue As InstantQueue
            If m_InstantQueue Is Nothing Then m_InstantQueue = New InstantQueue(Me)
            Return m_InstantQueue
        End Get
    End Property

    Public ReadOnly Property Token() As String Implements IAccessToken.Token
        Get
            Return m_AccessToken.Token
        End Get
    End Property

    Public ReadOnly Property TokenSecret() As String Implements IAccessToken.TokenSecret
        Get
            Return m_AccessToken.TokenSecret
        End Get
    End Property


    Public Function GetRentalHistory(ByVal historyType As RentalHistoryType, ByVal maxResults As Integer) As RentalHistoryCollection
        Dim result As New List(Of RentalHistoryItem)
        Dim runningStartIndex = 0

        Do
            Dim resource As RestCall

            Select Case historyType
                Case RentalHistoryType.All
                    resource = NetflixUrls.GetUsersRentalHistory(Me, runningStartIndex, Math.Min(100, maxResults - result.Count), Nothing)
                Case RentalHistoryType.Returned
                    resource = NetflixUrls.GetUsersRentalHistoryReturned(Me, runningStartIndex, Math.Min(100, maxResults - result.Count), Nothing)
                Case RentalHistoryType.Shipped
                    resource = NetflixUrls.GetUsersRentalHistoryShipped(Me, runningStartIndex, Math.Min(100, maxResults - result.Count), Nothing)
                Case RentalHistoryType.Watched
                    resource = NetflixUrls.GetUsersRentalHistoryWatched(Me, runningStartIndex, Math.Min(100, maxResults - result.Count), Nothing)
                Case Else : Throw New ArgumentException("Unknown rental history type", "historyType")
            End Select

            Dim listFragment = Connection.RequestXmlResource(resource, Me)
            If listFragment.<rental_history_item>.Count = 0 Then Exit Do
            For Each node In listFragment.<rental_history_item>
                result.Add(New RentalHistoryItem(Connection, node))
                If result.Count >= maxResults Then Exit For
            Next
            If result.Count >= maxResults Then Exit Do
            runningStartIndex += listFragment.<rental_history_item>.Count
        Loop

        Return New RentalHistoryCollection(result)
    End Function

    Public Function GetRecommedations(ByVal maxResults As Integer, ByVal expansions As TitleExpansions) As RecommendationCollection
        Dim result As New List(Of RecommendationItem)
        Dim runningStartIndex = 0

        Do
            Dim resource As RestCall

            resource = NetflixUrls.GetUsersRecommendations(Me, runningStartIndex, Math.Min(100, maxResults - result.Count), expansions)

            Dim listFragment = Connection.RequestXmlResource(resource, Me)
            If listFragment.<recommendation>.Count = 0 Then Exit Do
            For Each node In listFragment.<recommendation>
                result.Add(New RecommendationItem(Connection, node))
                If result.Count >= maxResults Then Exit For
            Next
            If result.Count >= maxResults Then Exit Do
            runningStartIndex += listFragment.<recommendation>.Count
        Loop

        Return New RecommendationCollection(result)
    End Function

    Public Function GetRatings(ByVal titleRefs As List(Of String)) As RatingCollection
        Dim result As New List(Of RatingItem)
        If (titleRefs Is Nothing) Then
            Return Nothing
        End If
        Dim firstTitleRef As String = titleRefs.Item(0)
        Dim additionalTitleRefs As String() = New String() {}
        If (titleRefs.Count > 1) Then
            additionalTitleRefs = titleRefs.GetRange(1, titleRefs.Count - 1).ToArray()
        End If

        Dim resource As RestCall

        resource = NetflixUrls.GetUsersRatingsActual(Me, firstTitleRef, additionalTitleRefs)

        Dim listFragment = Connection.RequestXmlResource(resource, Me)
        For Each node In listFragment.<ratings_item>
            result.Add(New RatingItem(Connection, node))
        Next

        Return New RatingCollection(result)
    End Function

    Public Sub SetRating(ByVal titleRef As String, ByVal newRating As String)
        Dim resource As RestCall

        resource = NetflixUrls.PostUsersRatingsActual(Me, titleRef, newRating.RatingEnum)

        Try
            Dim listFragment = Connection.RequestXmlResource(resource, Me)
        Catch ex As Exception
            If XElement.Parse(ex.Message).<status_code>.Value = "422" Then
                Dim currentRating As RatingItem = GetRatings(New List(Of String)(New String() {titleRef}))(0)
                resource = NetflixUrls.PutUsersRatingsActual(currentRating.Id.Replace("/title/", "/title/actual/"), newRating.RatingEnum)
                Dim listFragment = Connection.RequestXmlResource(resource, Me)
            End If
        End Try

    End Sub

    Public Sub AddUserRatings(ByRef recommendations As RecommendationCollection)
        Dim titleRefs As List(Of String) = New List(Of String)()
        For Each recommendation As RecommendationItem In recommendations
            titleRefs.Add(recommendation.Id)
        Next
        Dim ratings As RatingCollection = GetRatings(titleRefs)
        For Each itemRating As RatingItem In ratings
            For Each itemRecommendation As RecommendationItem In recommendations
                If itemRating.TitleRef = itemRecommendation.TitleRef Then
                    itemRecommendation.Source.Add(itemRating.Source.<user_rating>)
                    Exit For
                End If
            Next
        Next
    End Sub

    Public Sub AddUserRatings(ByRef catalogTitles As CatalogTitleCollection)
        Dim titleRefs As List(Of String) = New List(Of String)()
        For Each theTitle As CatalogTitle In catalogTitles
            titleRefs.Add(theTitle.Id)
        Next
        Dim ratings As RatingCollection = GetRatings(titleRefs)
        For Each itemRating As RatingItem In ratings
            For Each theTitle As CatalogTitle In catalogTitles
                If itemRating.TitleRef = theTitle.TitleRef Then
                    theTitle.Source.Add(itemRating.Source.<user_rating>)
                    Exit For
                End If
            Next
        Next
    End Sub
End Class
